#include "stdafx.h"

namespace cpputils
{

string to_string(int V)
{
	char Buf[numeric_limits<int>::digits10 + 3];
	sprintf(Buf, "%d", V);
	return Buf;
}

string to_string(unsigned int V)
{
	char Buf[numeric_limits<unsigned int>::digits10 + 2];
	sprintf(Buf, "%u", V);
	return Buf;
}

string to_string(long long V)
{
	if (V >= numeric_limits<int>::min() && V <= numeric_limits<int>::max())
		return to_string((int)V);
	stringstream Str;
	Str << V;
	return Str.str();
}

string to_string(unsigned long long V)
{
	if (V <= numeric_limits<unsigned int>::max())
		return to_string((unsigned int)V);
	stringstream Str;
	Str << V;
	return Str.str();
}

int to_int(const string& S)
{
	int V;
	char Ch;
	if (sscanf(S.c_str(), "%d %c", &V, &Ch) != 1) throw runtime_error("Invalid int: " + S);
	return V;
}

unsigned int to_unsigned_int(const string& S)
{
	unsigned int V;
	char Ch;
	if (sscanf(S.c_str(), "%u %c", &V, &Ch) != 1) throw runtime_error("Invalid unsigned int: " + S);
	return V;
}

long long to_long_long(const string& S)
{
	int V;
	char Ch;
	if (sscanf(S.c_str(), "%d %c", &V, &Ch) == 1) return V;
	long long VV;
	stringstream Str;
	if (!(Str >> VV) || Str >> Ch) throw runtime_error("Invalid long long: " + S);
	return VV;
}

unsigned long long to_unsigned_long_long(const string& S)
{
	unsigned int V;
	char Ch;
	if (sscanf(S.c_str(), "%u %c", &V, &Ch) == 1) return V;
	unsigned long long VV;
	stringstream Str;
	if (!(Str >> VV) || Str >> Ch) throw runtime_error("Invalid unsigned long long: " + S);
	return VV;
}

string to_string(float V)
{
	char Buf[numeric_limits<float>::digits10 + (numeric_limits<int>::digits10 + 1) + 5];
	sprintf(Buf, "%.*g", numeric_limits<float>::digits10 , V);
	return Buf;
}

string to_string(double V)
{
	char Buf[numeric_limits<double>::digits10 + (numeric_limits<int>::digits10 + 1) + 5];
	sprintf(Buf, "%.*g", numeric_limits<double>::digits10 , V);
	return Buf;
}

float to_float(const string& S)
{
	float V;
	char Ch;
	if (sscanf(S.c_str(), "%f %c", &V, &Ch) != 1) throw runtime_error("Invalid float: " + S);
	return V;
}

double to_double(const string& S)
{
	double V;
	char Ch;
	if (sscanf(S.c_str(), "%lf %c", &V, &Ch) != 1) throw runtime_error("Invalid double: " + S);
	return V;
}

string format_string(const char* Fmt, va_list Args)
{
	string S;
	for (S.resize(256); S.size() >= 256; S.resize(S.size() * 2))
	{
		int Len = vsnprintf(&S[0], S.size(), Fmt, Args);
		if (Len >= 0 && Len < (int)S.size()) return S.data();
	}
	throw runtime_error(string("Cannot format string: ") + Fmt);
}

string format_string(const char* Fmt, ...)
{
	scoped_va_list Args;
	va_start(Args.ptr, Fmt);
	return format_string(Fmt, Args.ptr);
}

vector<string> split_string(const string& S, char Ch)
{
	vector<string> Result;
	int Pos = 0;
	for (int I = 0; I < (int)S.length(); I++)
		if (S[I] == Ch)
		{
			Result.push_back(S.substr(Pos, I - Pos));
			Pos = I + 1;
		}
		Result.push_back(S.substr(Pos));
	return Result;
}

int checked_fprintf(FILE* File, const char* Fmt, va_list Args)
{
	int Result = vfprintf(File, Fmt, Args);
	if (Result < 0) throw runtime_error("Output error");
	return Result;
}

int checked_fprintf(FILE* File, const char* Fmt, ...)
{
	scoped_va_list Args;
	va_start(Args.ptr, Fmt);
	return checked_fprintf(File, Fmt, Args.ptr);
}

int checked_printf(const char* Fmt, va_list Args)
{
	return checked_fprintf(stdout, Fmt, Args);
}

int checked_printf(const char* Fmt, ...)
{
	scoped_va_list Args;
	va_start(Args.ptr, Fmt);
	return checked_fprintf(stdout, Fmt, Args.ptr);
}

FILE* checked_fopen(const string& Filename, const string& Mode)
{
	FILE* File = fopen(Filename.c_str(), Mode.c_str());
	if (File == 0) throw runtime_error("Cannot open file: " + Filename);
	return File;
}

string change_filename_ext(string S, const string& Ext)
{
	int I = S.length() - 1;
	while (I >= 0 && S[I] != '/' && S[I] != '\\' && S[I] != '.') I--;
	if (I >= 0 && S[I] == '.') S.erase(I);
	return S + "." + Ext;
}

}
